﻿using SuperMap.Data;
using SuperMap.Realspace;
using System;
using System.Collections.Generic;
using System.Data;
using System.Drawing;
using System.Windows.Forms;
using Ycjw.PipeLine.Map.Basic.Conditions;
using Ycjw.PipeLine.Map.Basic.SuperMap;

namespace Ycjw.PipeLine.Map.Tools.Conditions
{
    /// <summary>
    /// 追踪分析
    /// </summary>
    public class ZZAnalystToolBar:BasicToolBar
    {
        enum FindTyp
        {
            /// <summary>
            /// 上游分析
            /// </summary>
            From,
            /// <summary>
            /// 下游分析
            /// </summary>
            To,
            /// <summary>
            /// 双向分析
            /// </summary>
            Both
        }
        private readonly string ATTR_SSFNODE = "SSFNODE";
        private readonly string ATTR_SSTNODE = "SSTNODE";
        private readonly string ATTR_SSNODEID = "SSNODEID";

        private readonly string TXT_PRENODETXT = "上游";
        private readonly string TXT_NEXTNODETXT = "下游";
        public ZZAnalystToolBar()
        {
            this.ConditionPanelName = "追踪分析";

            var annlystToolStripButtonPre = new ToolStripButton()
            {
                DisplayStyle = ToolStripItemDisplayStyle.ImageAndText,
                Text = "上游追踪",
                Name = "preAnalyst"
            };
            base.ToolStrip.Items.Add(annlystToolStripButtonPre);

            var annlystToolStripButtonNext = new ToolStripButton()
            {
                DisplayStyle = ToolStripItemDisplayStyle.ImageAndText,
                Text = "下游追踪",
                Name = "nextAnalyst"
            };
            base.ToolStrip.Items.Add(annlystToolStripButtonNext);

            var annlystToolStripButtonBoth = new ToolStripButton()
            {
                DisplayStyle = ToolStripItemDisplayStyle.ImageAndText,
                Text = "双向追踪",
                Name = "bothAnalyst"
            };
            base.ToolStrip.Items.Add(annlystToolStripButtonBoth);

            annlystToolStripButtonPre.Click += AnnlystToolStripButton_Click;
            annlystToolStripButtonNext.Click += AnnlystToolStripButton_Click ;
            annlystToolStripButtonBoth.Click += AnnlystToolStripButton_Click ;
        }
        private void DrawWhenSelectNetWork(FindTyp ft, Layer3DDataset l3d, Selection3D s3d)
        {            
            if (!(l3d.Dataset is DatasetVector)) return;
            DatasetVector datasetVectorNetWork = l3d.Dataset as DatasetVector;
            DatasetVector dsvPoint = this.FindNetWorkNodeLayerByLineLayer(l3d.Name);

            var currentLineSMID = "-1";

            var fs = s3d.ToRecordset().GetAllFeatures();
            if (fs.Count < 1) return;
            foreach (var f in fs.Values)
            {
                currentLineSMID = f.GetString("SmID");
                break;
            }
            if (currentLineSMID == "-1") return;

            if (datasetVectorNetWork == null) return;

            var fsInNodeLayer = dsvPoint.GetAllFeatures();
            var fsInNetWorkLayer = datasetVectorNetWork.GetAllFeatures();

            var nodeIDs = GetPreNextNodesIDByNetWorkSmid(datasetVectorNetWork, currentLineSMID, ft);

            if (ft == FindTyp.From || ft == FindTyp.Both)
            {
                var endPoint3D = (fsInNetWorkLayer[int.Parse(currentLineSMID)].GetGeometry() as GeoLine3D).InnerPoint3D;
                var end = new GeoPoint3D(endPoint3D);
                foreach (var val in nodeIDs[FindTyp.From])
                {
                    var indexStart = int.Parse(val);
                    if (indexStart > -1)
                    {
                        var start = fsInNodeLayer[indexStart].GetGeometry() as GeoPoint3D;
                        DrawLineWithLabel(start, end, TXT_PRENODETXT);

                        Scene.Fly(LookAtGeoPoint3D(start), 2000, false);
                    }
                }
                if (ft == FindTyp.Both)
                {
                    foreach (var val in nodeIDs[FindTyp.To])
                    {
                        var indexEnd = int.Parse(val);
                        if (indexEnd > -1)
                        {
                            var endEnd = fsInNodeLayer[indexEnd].GetGeometry() as GeoPoint3D;
                            DrawLineWithLabel(end, endEnd, "", TXT_NEXTNODETXT);
                        }
                    }
                }
            }
            if (ft == FindTyp.To)
            {
                var startPoint3d = (fsInNetWorkLayer[int.Parse(currentLineSMID)].GetGeometry() as GeoLine3D).InnerPoint3D;
                var start = new GeoPoint3D(startPoint3d);
                foreach (var val in nodeIDs[FindTyp.To])
                {
                    var indexEnd = int.Parse(val);
                    if (indexEnd > -1)
                    {
                        var end = fsInNodeLayer[indexEnd].GetGeometry() as GeoPoint3D;
                        DrawLineWithLabel(start, end, "", TXT_NEXTNODETXT);
                    }
                }
                Scene.Fly(LookAtGeoPoint3D(start), 2000, false);
            }
        }
        private void DrawWhenSelectPoint(FindTyp ft, Layer3DDataset l3d, Selection3D s3d)
        {
            if (!(l3d.Dataset is DatasetVector)) return;
            DatasetVector dsvPoint = l3d.Dataset as DatasetVector;

            var nodeid = "-1";
            DatasetVector realDatasetVector = null;
            if (dsvPoint.FieldInfos.IndexOf(ATTR_SSNODEID) < 0)
            {
                int smid = GetRealNode(dsvPoint, ref realDatasetVector);
                if (smid == -1) return;
                nodeid = realDatasetVector.GetAllFeatures()[smid].GetString(ATTR_SSNODEID);
            }
            else
            {
                var fs = s3d.ToRecordset().GetAllFeatures();
                if (fs.Count < 1) return;
                foreach (var f in fs.Values)
                {
                    nodeid = f.GetString(ATTR_SSNODEID);
                    break;
                }
            }
            if (nodeid == "-1") return;

            DatasetVector datasetVectorNetWork = FindNetWorkLayerByNodeLayer(l3d.Name);
            if (datasetVectorNetWork == null) return;

            var fsInNodeLayer = dsvPoint.GetAllFeatures();
            var nodeIDs = GetPreNextNodesID(datasetVectorNetWork, nodeid, ft);

            if (ft == FindTyp.From || ft == FindTyp.Both)
            {
                var end = fsInNodeLayer[int.Parse(nodeid)].GetGeometry() as GeoPoint3D;
                foreach (var val in nodeIDs[FindTyp.From])
                {
                    var indexStart = int.Parse(val);
                    if (indexStart > -1)
                    {
                        var start = fsInNodeLayer[indexStart].GetGeometry() as GeoPoint3D;
                        DrawLineWithLabel(start, end, TXT_PRENODETXT);

                        Scene.Fly(LookAtGeoPoint3D(start), 2000, false);
                    }
                }
                if (ft == FindTyp.Both)
                {
                    foreach (var val in nodeIDs[FindTyp.To])
                    {
                        var indexEnd = int.Parse(val);
                        if (indexEnd > -1)
                        {
                            var endEnd = fsInNodeLayer[indexEnd].GetGeometry() as GeoPoint3D;
                            DrawLineWithLabel(end, endEnd, "", TXT_NEXTNODETXT);
                        }
                    }
                }
            }
            if (ft == FindTyp.To)
            {
                var start = fsInNodeLayer[int.Parse(nodeid)].GetGeometry() as GeoPoint3D;
                foreach (var val in nodeIDs[FindTyp.To])
                {
                    var indexEnd = int.Parse(val);
                    if (indexEnd > -1)
                    {
                        var end = fsInNodeLayer[indexEnd].GetGeometry() as GeoPoint3D;
                        DrawLineWithLabel(start, end, "", TXT_NEXTNODETXT);
                    }
                }
                Scene.Fly(LookAtGeoPoint3D(start), 2000, false);
            }
        }
        private void AnnlystToolStripButton_Click(object sender, EventArgs e)
        {
            Scene.TrackingLayer.Clear();
            FindTyp ft;
            ToolStripButton tsb = sender as ToolStripButton;
            if (tsb.Name == "preAnalyst")
            {
                ft = FindTyp.From;
            }
            else if (tsb.Name == "nextAnalyst")
            {
                ft = FindTyp.To;
            }
            else
            {
                ft = FindTyp.Both;
            }
            var selections = Scene.FindSelection(true);
            if (selections == null) return;
            foreach (Selection3D s3d in selections)
            {
                if (s3d.Count > 1)
                {
                    Sunny.UI.UIMessageBox.ShowWarning("请只选择一个网点或者管线");
                    return;
                }
                if (s3d.Layer.Type != Layer3DType.Dataset) continue;
                if (!(s3d.Layer is Layer3DDataset)) continue;
                Layer3DDataset l3d = s3d.Layer as Layer3DDataset;
                //没有选中点或者线-忽略
                if (l3d.Dataset.Type == SuperMap.Data.DatasetType.Point3D)
                {
                    DrawWhenSelectPoint(ft, l3d, s3d);
                }
                else if (l3d.Dataset.Type == SuperMap.Data.DatasetType.Network3D)
                {
                    DrawWhenSelectNetWork(ft, l3d, s3d);
                }
                return;
            }
            Sunny.UI.UIMessageTip.ShowWarning("请先选择一个节点");
        }

        private int GetRealNode(DatasetVector select,ref DatasetVector realDatasetVector)
        {
            foreach (Layer3D lyr in this.Scene.Layers)
            {
                if (!(lyr is Layer3DDataset)) continue;
                Layer3DDataset l3d = lyr as Layer3DDataset;
                if (l3d.Dataset.Type != SuperMap.Data.DatasetType.Point) continue;
                if (!(l3d.Dataset is DatasetVector)) continue;

                DatasetVector dsv = l3d.Dataset as DatasetVector;

                if (dsv.FieldInfos.IndexOf(ATTR_SSFNODE) < 0) continue;
                var ids = dsv.GetIDsByGeoRelation(select, SpatialRelationType.Intersect, true, true);
                if (ids != null && ids.Length > 0) 
                {
                    realDatasetVector = dsv;
                    return ids[0];
                }
            }
            return -1;
        }

        private LookAt LookAtGeoPoint3D(GeoPoint3D point)
        {
            LookAt lk = new LookAt();
            lk.Longitude = point.X;
            lk.Latitude = point.Y;
            lk.Heading = 150;
            lk.Altitude = point.Z;
            lk.Tilt = 72;
            lk.Range = 1000;
            lk.AltitudeMode = AltitudeMode.RelativeToGround;
            return lk;
        }

        private void DrawLineWithLabel(GeoPoint3D pStart, GeoPoint3D pEnd,string startLabel = "",string endLabel = "")
        {
            Point3Ds p3ds = new Point3Ds();
            p3ds.Add(pStart.InnerPoint3D);
            p3ds.Add(pEnd.InnerPoint3D);
            GeoLine3D gl3 = new GeoLine3D(p3ds)
            {
                Style3D = new GeoStyle3D()
                {
                    AltitudeMode = AltitudeMode.Absolute,
                    LineColor = Color.Yellow,
                    LineWidth = 4
                }
            };
            Scene.TrackingLayer.Add(gl3,"");
            var markerPath = Commons.Paths.ApplicationResourcesDir + "\\Symbols\\downArrow.gif";

            var marderStyle = new GeoStyle3D()
            {
                MarkerColor = Color.Green,
                MarkerSize = 40,
                MarkerFile = markerPath,
                AltitudeMode = AltitudeMode.Absolute,
                MarkerScale = 0.25
            };
            if (!string.IsNullOrEmpty(startLabel))
            {
                var textLocation = pStart.InnerPoint3D;
                GeoText3D geoText = new GeoText3D(new TextPart3D(startLabel, textLocation));
                Styles.SetResultTextStyle(geoText);
                Scene.TrackingLayer.Add(geoText, "");
                pStart.Style3D = marderStyle;
                Scene.TrackingLayer.Add(pStart, "");
            }
            if (!string.IsNullOrEmpty(endLabel))
            {
                var textLocation = pEnd.InnerPoint3D;
                GeoText3D geoText = new GeoText3D(new TextPart3D(endLabel, textLocation));
                Styles.SetResultTextStyle(geoText);
                Scene.TrackingLayer.Add(geoText, "");
                marderStyle.MarkerColor = Color.Red;
                pEnd.Style3D = marderStyle;
                Scene.TrackingLayer.Add(pEnd, "");
            }
        }
        private Dictionary<FindTyp, string[]> GetPreNextNodesIDByNetWorkSmid(DatasetVector datasetVectorNetWork, string currentSMID, FindTyp findType)
        {
            var smidFieldName = "SmID";
            var results = new Dictionary<FindTyp, string[]>();
            DatasetVectorEx dve = new DatasetVectorEx(datasetVectorNetWork.Name)
            {
                HasGeometry = false,
                DatasetVector = datasetVectorNetWork
            };
            List<string> result = new List<string>();
            dve.ResultFields.Clear();
            dve.ResultFields.Add(ATTR_SSFNODE);
            dve.ResultFields.Add(ATTR_SSTNODE);
            var toNodeIDDT = dve.Query(smidFieldName + " = " + currentSMID);
            if (toNodeIDDT.Rows.Count > 0)
            {
                foreach (DataRow dr in toNodeIDDT.Rows)
                {
                    var fromNodeID = dr[ATTR_SSFNODE];
                    if (fromNodeID != null)
                    {
                        result.Add(fromNodeID.ToString());
                        results.Add(FindTyp.From, result.ToArray());
                    }
                    result.Clear();
                    var toNodeID = dr[ATTR_SSTNODE];
                    if (toNodeID != null)
                    {
                        result.Add(toNodeID.ToString());
                        results.Add(FindTyp.To, result.ToArray());
                    }
                }
            }

            return results;
        }
        private Dictionary<FindTyp, string[]> GetPreNextNodesID(DatasetVector datasetVectorNetWork,string currentNodeID, FindTyp findType)
        {
            var results = new Dictionary<FindTyp, string[]>();
            DatasetVectorEx dve = new DatasetVectorEx(datasetVectorNetWork.Name)
            {
                HasGeometry = false,
                DatasetVector = datasetVectorNetWork
            };
            if (findType == FindTyp.From || findType == FindTyp.Both)
            {
                List<string> result = new List<string>();
                dve.ResultFields.Clear();
                dve.ResultFields.Add(ATTR_SSFNODE);
                var toNodeIDDT = dve.Query(ATTR_SSTNODE + " = " + currentNodeID);
                if(toNodeIDDT.Rows.Count > 0)
                {
                    foreach (DataRow dr in toNodeIDDT.Rows)
                    {
                        var toNodeID = dr[ATTR_SSFNODE];
                        if (toNodeID != null)
                            result.Add(toNodeID.ToString());
                    }
                }
                else
                {
                    result.Add("-1");
                }
                results.Add(FindTyp.From, result.ToArray());
            }
            if (findType == FindTyp.To || findType == FindTyp.Both)
            {
                List<string> result = new List<string>();
                dve.ResultFields.Clear();
                dve.ResultFields.Add(ATTR_SSTNODE);
                var fromNodeIDDT = dve.Query(ATTR_SSFNODE + " = " + currentNodeID);

                if (fromNodeIDDT.Rows.Count > 0)
                {
                    foreach (DataRow dr in fromNodeIDDT.Rows)
                    {
                        var fromNodeID = dr[ATTR_SSTNODE];
                        if (fromNodeID != null)
                            result.Add(fromNodeID.ToString());
                    }
                }
                else
                {
                    result.Add("-1");
                }
                results.Add(FindTyp.To, result.ToArray());
            }

            return results;
        }

        private DatasetVector FindNetWorkLayerByNodeLayer(string nodeLayerName)
        {
            var neetLayerName = nodeLayerName.Replace("_Node@","@");
            if(neetLayerName.Contains("#"))
            neetLayerName = neetLayerName.Substring(0,neetLayerName.LastIndexOf("#"));
            foreach (Layer3D lyr in this.Scene.Layers)
            {
                if (lyr.Name != neetLayerName) continue;

                if (!(lyr is Layer3DDataset)) continue;
                Layer3DDataset l3d = lyr as Layer3DDataset;
                if (l3d.Dataset.Type != SuperMap.Data.DatasetType.Network3D && l3d.Dataset.Type != SuperMap.Data.DatasetType.Network) continue;
                if (!(l3d.Dataset is DatasetVector)) continue;

                DatasetVector dsv = l3d.Dataset as DatasetVector;

                if (dsv.FieldInfos.IndexOf(ATTR_SSFNODE) < 0) continue;
                if (dsv.FieldInfos.IndexOf(ATTR_SSTNODE) < 0) continue;
                return dsv;
            }
            return null;
        }
        private DatasetVector FindNetWorkNodeLayerByLineLayer(string lineLayerName)
        {
            var neetLayerName = lineLayerName.Replace("@", "_Node@");
            foreach (Layer3D lyr in this.Scene.Layers)
            {
                if (lyr.Name != neetLayerName) continue;

                if (!(lyr is Layer3DDataset)) continue;
                Layer3DDataset l3d = lyr as Layer3DDataset;
                if (l3d.Dataset.Type != SuperMap.Data.DatasetType.Point3D) continue;
                if (!(l3d.Dataset is DatasetVector)) continue;

                DatasetVector dsv = l3d.Dataset as DatasetVector;

                if (dsv.FieldInfos.IndexOf(ATTR_SSNODEID) < 0) continue;
                return dsv;
            }
            return null;
        }

        public override void AfterClose()
        {
            Scene.TrackingLayer.Clear();
        }
    }
}
